import { SHAPES } from "./shape";

function randomInt() {
    return ~~(1000 * Math.random());
}

function getRotatePosition(position, form, right, bottom) {
    return {
        x: Math.min(position.x, right - form.width),
        y: Math.min(position.y, bottom - form.height)
    };
}

export class Block {
    constructor(shapeIndex, rotateIndex = randomInt()) {
        this._position = { x: 0, y: 0 };

        this.shape = SHAPES[shapeIndex % SHAPES.length];
        this.rotateIndex = rotateIndex % this.shape.forms.length;
    }

    rotate(width = Infinity, height = Infinity) {
        this.rotateIndex = (this.rotateIndex + 1) % this.shape.forms.length;
        const p = getRotatePosition(this.position, this.current, width, height);
        return this.setPosition(p);
    }

    moveLeft() {
        if (this.left > 0) {
            this.position.x--;
        }
        return this;
    }

    moveRight(width = Infinity) {
        if (this.right + 1 < width) {
            this.position.x++;
        }
        return this;
    }

    moveDown(height = Infinity) {
        if (this.bottom + 1 < height) {
            this.position.y++;
        }
    }

    setPosition(x, y) {
        if (typeof x === "object") {
            y = x.y;
            x = x.x;
        }

        this.position.x = x;
        this.position.y = y;
        return this;
    }

    getCoors() {
        return this.current.map(point => ({
            x: point.x + this.left,
            y: point.y + this.top
        }));
    }

    get current() {
        return this.shape.forms[this.rotateIndex];
    }

    get width() {
        return this.current.width;
    }

    get height() {
        return this.current.height;
    }

    get left() {
        return this.position.x;
    }

    get top() {
        return this.position.y;
    }

    get right() {
        return this.left + this.width - 1;
    }

    get bottom() {
        return this.top + this.height - 1;
    }

    get position() {
        return this._position;
    }

    get color() {
        return this.shape.colorClass;
    }

    fastenOffset(offsetX, offsetY) {
        return this.fasten(this.left + offsetX, this.top + offsetY);
    }

    fastenRotate(width = Infinity, height = Infinity) {
        const nextIndex = (this.rotateIndex + 1) % this.shape.forms.length;
        const next = this.shape.forms[nextIndex];
        const p = getRotatePosition(this.position, next, width, height);
        return this.fasten(p.x, p.y, next);
    }

    fasten(left = this.left, top = this.top, form = this.current) {
        return form
            .map(part => ({
                x: left + part.x,
                y: top + part.y,
                c: this.color
            }))
            .filter(t => t.x >= 0 && t.y >= 0);
    }
}

export class BlockFactory {
    static get default() {
        return (this._default || (this._default = new BlockFactory));
    }

    shapes() {
        SHAPES;
    }

    create() {
        return new Block(randomInt());
    }
}
